<template>
  <div style="position: relative; overflow: hidden">
    <div id="map" style="width: 100vw; height: 100vh"></div>
    <div
      v-for="(item, index) in popupData"
      :key="index"
      class="popup"
      :style="{
        left: item.x + 'px',
        top: item.y + 'px',
      }"
    ></div>
  </div>
</template>

<script>
import { default as proj4 } from "proj4";
import * as Cesium from "cesium";
import "cesium/Build/Cesium/Widgets/widgets.css";
import data from "../assets/data/taipo";
import * as turf from "@turf/turf";

let viewer;
let xdiff;
let ydiff;

export default {
  name: "cesium",
  data() {
    return {
      popupData: [],
    };
  },
  methods: {
    initMap() {
      let that = this;

      Cesium.Ion.defaultAccessToken =
        "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI2ZTgxOGNhZC03NThmLTQ0NzMtOTNlYS1kNmM3YzlmZDU3NTMiLCJpZCI6MTI1NTY3LCJpYXQiOjE2NzY5MDI0MzJ9.ulIEz3NCh2cMEBiHrqIuv9I6icn5KTMMnBdy2wassoM";
      viewer = new Cesium.Viewer("map", {
        // 配置项
        infoBox: false,
        animation: false, // 禁用动画控件
        timeline: false, // 禁用时间线控件
        homeButton: false, // 禁用Home按钮
        sceneModePicker: false, // 禁用场景模式选择器
        baseLayerPicker: false, // 禁用图层选择器
        navigationHelpButton: false, // 禁用帮助按钮
        fullscreenButton: false, // 禁用全屏按钮
        geocoder: false, // 禁用搜索框
        requestRenderMode: true, // 显示渲染
        maximumRenderTimeChange: Infinity,
        navigation: false,
      });

      let imageryLayers = viewer.imageryLayers;
      // 移出Cesium底图
      imageryLayers.removeAll();
      // 添加天地图
      let imagery = imageryLayers.addImageryProvider(
        new Cesium.WebMapTileServiceImageryProvider({
          url: "http://t0.tianditu.gov.cn/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=vec&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=f69df935f2b4e5d06629d91c56be2809",
          format: "image/png",
          layer: "",
          style: "",
          tileMatrixSetID: "",
        })
      );
      imageryLayers.addImageryProvider(
        new Cesium.WebMapTileServiceImageryProvider({
          url: "http://t0.tianditu.gov.cn/cia_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=cia&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=f69df935f2b4e5d06629d91c56be2809",
          format: "image/png",
          layer: "",
          style: "",
          tileMatrixSetID: "",
        })
      );

      viewer.scene.globe.baseColor = new Cesium.Color(
        15 / 255,
        33 / 255,
        47 / 255
      );
      imagery.contrast = -1.5;
      imagery.alpha = 0.2;

      viewer.scene.postRender.addEventListener((e) => {
        that.addPopup();
      });
    },
    tranformCoordinate() {
      Cesium.GeoJsonDataSource.crsNames["urn:ogc:def:crs:EPSG::2326"] =
        Cesium.GeoJsonDataSource.crsNames["EPSG::2326"] = (coordinates) => {
          const fromProjection = `PROJCS["Hong Kong 1980 Grid System",GEOGCS["Hong Kong 1980",DATUM["Hong_Kong_1980",SPHEROID["International 1924",6378388,297],TOWGS84[-162.619,-276.959,-161.764,-0.067753,2.243648,1.158828,-1.094246]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4611"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",22.3121333333333],PARAMETER["central_meridian",114.178555555556],PARAMETER["scale_factor",1],PARAMETER["false_easting",836694.05],PARAMETER["false_northing",819069.8],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AUTHORITY["EPSG","2326"]]`;

          const toProjection = `GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]`;

          const x = coordinates[0];
          const y = coordinates[1];

          const newCoordinates = proj4(fromProjection, toProjection, [x, y]);
          return Cesium.Cartesian3.fromDegrees(
            newCoordinates[0],
            newCoordinates[1],
            0
          );
        };
    },
    addGeoJson(url) {
      let that = this;
      var dataSource = new Cesium.GeoJsonDataSource();
      dataSource
        .load(url, {
          stroke: new Cesium.Color.fromBytes(97, 137, 154),
          fill: new Cesium.Color(49 / 255, 70 / 255, 87 / 255, 0.5),
        })
        .then(function () {
          viewer.dataSources.add(dataSource);
          viewer.zoomTo(dataSource);
        });
    },
    setView(x, y, z = 100000) {
      if (x instanceof Array || y instanceof Array) {
        viewer.camera.setView({
          destination: Cesium.Rectangle.fromDegrees(
            ...handleRectangleDegrees(x, y)
          ),
          duration: 0,
          complete: () => {},
        });
      } else {
        viewer.camera.setView({
          destination: Cesium.Cartesian3.fromDegrees(x, y, z),
          duration: 0,
          complete: () => {},
        });
      }
    },
    addPopup() {
      this.popupData = [];
      let arr = [
        {
          show: true,
          postiton: [113.516554832785, 22.7815541566398],
        },
        {
          show: true,
          postiton: [113.565595110563, 22.8119042280145],
        },
        {
          show: true,
          postiton: [113.585566261118, 22.7467959068676],
        },
        {
          show: true,
          postiton: [113.585561647606, 22.7467922756939],
        },
        {
          show: true,
          postiton: [113.585544380734, 22.7468031264434],
        },
        {
          show: true,
          postiton: [113.5250091611, 22.796468624824],
        },
        {
          show: true,
          postiton: [113.53501380961, 22.7752535345139],
        },
        {
          show: true,
          postiton: [113.606360650159, 22.7673058506878],
        },
        {
          show: true,
          postiton: [113.575970393566, 22.8011478781795],
        },
        {
          show: true,
          postiton: [113.48319856831, 22.8434974846255],
        },
        {
          show: true,
          postiton: [113.483183010224, 22.8434759099068],
        },
        {
          show: true,
          postiton: [113.521532982952, 22.7202557655554],
        },
        {
          show: true,
          postiton: [113.53274534813, 22.7955110445971],
        },
        {
          show: true,
          postiton: [113.584525474457, 22.7676399422363],
        },
        {
          show: true,
          postiton: [113.54157885687, 22.8101993251604],
        },
        {
          show: true,
          postiton: [113.540344472305, 22.7983192314786],
        },
        {
          show: true,
          postiton: [113.536264743559, 22.7850303729224],
        },
        {
          show: true,
          postiton: [113.5897553783, 22.7504601423855],
        },
        {
          show: true,
          postiton: [113.513549642677, 22.8011357132934],
        },
        {
          show: true,
          postiton: [113.665260156322, 22.6558535329566],
        },
        {
          show: true,
          postiton: [113.665242814055, 22.6540658381607],
        },
        {
          show: true,
          postiton: [113.540721493798, 22.8003300912433],
        },
        {
          show: true,
          postiton: [113.526640076431, 22.6870157770143],
        },
        {
          show: true,
          postiton: [113.494998793222, 22.8129609109105],
        },
        {
          show: true,
          postiton: [113.593364200102, 22.743924187381],
        },
        {
          show: true,
          postiton: [113.540681930867, 22.8078782923931],
        },
        {
          show: true,
          postiton: [113.550853128856, 22.7614672586024],
        },
        {
          show: true,
          postiton: [113.517482495539, 22.7849363232933],
        },
        {
          show: true,
          postiton: [113.662701458716, 22.6466855872565],
        },
        {
          show: true,
          postiton: [113.594501573329, 22.7505207744991],
        },
        {
          show: true,
          postiton: [113.597951948579, 22.7769371796389],
        },
        {
          show: true,
          postiton: [113.550305763681, 22.7620551543094],
        },
        {
          show: true,
          postiton: [113.568432803916, 22.7563407873987],
        },
        {
          show: true,
          postiton: [113.525835234783, 22.7976826914486],
        },
        {
          show: true,
          postiton: [113.536859093935, 22.8207334899539],
        },
        {
          show: true,
          postiton: [113.533484184956, 22.8106796700382],
        },
        {
          show: true,
          postiton: [113.561286394469, 22.6576939900548],
        },
        {
          show: true,
          postiton: [113.517806458323, 22.7815962791158],
        },
        {
          show: true,
          postiton: [113.516595454663, 22.6914001747332],
        },
        {
          show: true,
          postiton: [113.542308151213, 22.7973896718941],
        },
        {
          show: true,
          postiton: [113.603754064104, 22.7708103375522],
        },
        {
          show: true,
          postiton: [113.513533350975, 22.8012006043278],
        },
        {
          show: true,
          postiton: [113.514669619202, 22.7985178250092],
        },
        {
          show: true,
          postiton: [113.518584605796, 22.8266911342335],
        },
        {
          show: true,
          postiton: [113.514671591971, 22.7985149161823],
        },
        {
          show: true,
          postiton: [113.514672523459, 22.7985136999894],
        },
        {
          show: true,
          postiton: [113.514673302842, 22.7985119821778],
        },
        {
          show: true,
          postiton: [113.525831173412, 22.797677088093],
        },
        {
          show: true,
          postiton: [113.525822803781, 22.7976688379218],
        },
        {
          show: true,
          postiton: [113.525828709136, 22.7976751872076],
        },
        {
          show: true,
          postiton: [113.525826808323, 22.7976734135123],
        },
        {
          show: true,
          postiton: [113.52583358882, 22.7976798836908],
        },
        {
          show: true,
          postiton: [113.566106350839, 22.801166199545],
        },
        {
          show: true,
          postiton: [113.566111262961, 22.801242665269],
        },
        {
          show: true,
          postiton: [113.543064161582, 22.783263992993],
        },
        {
          show: true,
          postiton: [113.598001030574, 22.7770088898555],
        },
        {
          show: true,
          postiton: [113.54068188311, 22.8078570901731],
        },
        {
          show: true,
          postiton: [113.540569108785, 22.7957774034675],
        },
        {
          show: true,
          postiton: [113.517826225587, 22.7816572777368],
        },
        {
          show: true,
          postiton: [113.536864075158, 22.8207324208513],
        },
        {
          show: true,
          postiton: [113.536869022012, 22.8207302807108],
        },
        {
          show: true,
          postiton: [113.533496690806, 22.810679262368],
        },
        {
          show: true,
          postiton: [113.540554780068, 22.7958167856627],
        },
        {
          show: true,
          postiton: [113.54905183958, 22.8055537524493],
        },
        {
          show: true,
          postiton: [113.56644295678, 22.800544710883],
        },
        {
          show: true,
          postiton: [113.544432042623, 22.8030296675129],
        },
        {
          show: true,
          postiton: [113.495158864878, 22.797248092325],
        },
        {
          show: true,
          postiton: [113.516579222339, 22.6914439526023],
        },
        {
          show: true,
          postiton: [113.508136024199, 22.8503121640053],
        },
        {
          show: true,
          postiton: [113.533490103578, 22.8106792430909],
        },
        {
          show: true,
          postiton: [113.533503339525, 22.8106780998189],
        },
        {
          show: true,
          postiton: [113.533507664509, 22.8106782867513],
        },
        {
          show: true,
          postiton: [113.535007260258, 22.7752425504507],
        },
        {
          show: true,
          postiton: [113.575976679637, 22.8011399549163],
        },
        {
          show: true,
          postiton: [113.566459714017, 22.8005430389587],
        },
        {
          show: true,
          postiton: [113.525965071626, 22.8307287822828],
        },
        {
          show: true,
          postiton: [113.513273902813, 22.7829777203857],
        },
        {
          show: true,
          postiton: [113.532746424803, 22.7955034671885],
        },
      ];
      for (let i = 0; i <= arr.length - 1; i++) {
        let position = Cesium.Cartesian3.fromDegrees(...arr[i].postiton, 0);
        let box1 = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
          viewer.scene,
          position
        );
        for (let j = i + 1; j <= arr.length - 1; j++) {
          let position = Cesium.Cartesian3.fromDegrees(...arr[j].postiton, 0);
          let box2 = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
            viewer.scene,
            position
          );
          let flag = this.collision(box1, box2);
          if (flag) {
            arr[j].show = false;
          }
        }
      }
      arr.forEach((item) => {
        if (item.show) {
          let position = Cesium.Cartesian3.fromDegrees(...item.postiton, 0);
          let box = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
            viewer.scene,
            position
          );
          this.popupData.push(box);
        }
      });
    },
    collision(box1, box2) {
      let width = 75;
      let height = 75;
      let left = Math.max(box1.x, box2.x);
      let top = Math.max(box1.y, box2.y);
      let right = Math.min(box1.x + width, box2.x + width);
      let bottom = Math.min(box1.y + height, box2.y + height);
      if (left < right && top < bottom) {
        return true;
      } else {
        return false;
      }
    },
    // 添加点
    addPointsPrimitives() {
      // 点
      const length = data.junction_id.length;
      const pointsGeometry = [];
      for (let index = 0; index <= length - 1; index++) {
        pointsGeometry.push(
          new Cesium.GeometryInstance({
            geometry: new Cesium.CircleGeometry({
              center: Cesium.Cartesian3.fromDegrees(
                data.junction_y[index],
                data.junction_x[index]
              ),
              height: data.junction_elev[index],
              radius: 2,
            }),
            id: { id: data.junction_id[index], name: "point" },
            attributes: {
              color: new Cesium.ColorGeometryInstanceAttribute(
                7 / 255,
                213 / 255,
                11 / 255,
                1
              ),
            },
          })
        );
      }

      viewer.scene.primitives.add(
        new Cesium.Primitive({
          geometryInstances: pointsGeometry,
          releaseGeometryInstances: false,
          appearance: new Cesium.PerInstanceColorAppearance({
            flat: true,
            translucent: false,
          }),
        })
      );
    },
    drawIsoline() {
      var xmin = Number.MAX_VALUE;
      var ymin = Number.MAX_VALUE;
      var xmax = 0;
      var ymax = 0;

      data.junction_x.forEach((x) => {
        xmax = Math.max(x, xmax);
        xmin = Math.min(x, xmin);
      });

      data.junction_y.forEach((y) => {
        ymax = Math.max(y, ymax);
        ymin = Math.min(y, ymin);
      });

      let extent = [xmin, ymin, xmax, ymax];
      // extent: (4) [22.43289290754625, 114.15093311964198, 22.46633197583723, 114.19288675500377]
      let _points = {
        value: data.junction_pressure,
        x: data.junction_x,
        y: data.junction_y,
      };
      var max = Math.max.apply(null, data.junction_pressure);
      var min = Math.min.apply(null, data.junction_pressure);
      console.log(extent, _points, max, min);
      let gradeBreak = [-5.356140235022675, 19, 42, 65, 88, 110.88428992704108];

      function isoband(extent, points, gradeBreak) {
        var p = 2;
        //将区域等分20，获得每个等分点的坐标
        var pointGrid = pointGrid1(extent, 20, 20);
        //插值
        var t = points.value;
        var xa = points.x;
        var ya = points.y;
        var classf = [];
        var data = [];
        for (var i = 0; i < pointGrid.length; i++) {
          var x = pointGrid[i].x;
          var y = pointGrid[i].y;
          var value = predict(x, y, t, xa, ya, p);
          if (!isInArray(classf, y)) {
            classf.push(y);
            classf.sort(function (x, y) {
              //比较函数，排序
              if (x < y) {
                return -1;
              } else if (x > y) {
                return 1;
              } else {
                return 0;
              }
            });
            data.splice(classf.indexOf(y), 0, []); //在第y处添加[]
          }
          var dataIndex = classf.indexOf(y);
          data[dataIndex].push(value);
        }

        xdiff = (extent[2] - extent[0]) / (data[0].length - 1);
        ydiff = (extent[3] - extent[1]) / (data.length - 1);
        var isoBands = [];
        for (var i = 1; i < gradeBreak.length; i++) {
          var lowerBand = parseInt(gradeBreak[i - 1]);
          var upperBand = parseInt(gradeBreak[i]);
          var band = MarchingSquaresJS.isoBands(
            data,
            lowerBand,
            upperBand - lowerBand,
            {
              successCallback: function (bands) {
                bands.forEach((band, j) => {
                  band.forEach((p, k) => {
                    if (p[0] <= data[0].length && p[1] <= data.length) {
                      p[0] = extent[0] + p[0] * xdiff;
                      p[1] = extent[1] + p[1] * ydiff;
                    }
                  });
                });
              },
              verbose: true,
              polygons: true,
              inearRing: false,
              noQuadTree: false,
            }
          );
          isoBands.push({ coords: band, level: i, val: gradeBreak[i] });
        }
        return isoBands;
      }
      function pointGrid1(extent, xGridNum, yGridNum) {
        //等分区域
        var dx = (extent[2] - extent[0]) / xGridNum;
        var dy = (extent[3] - extent[1]) / yGridNum;
        var points = [];
        for (var i = 0; i < xGridNum + 1; i++) {
          for (var j = 0; j < yGridNum + 1; j++) {
            var x = extent[0] + i * dx;
            var y = extent[1] + j * dy;
            points.push({ x: x, y: y });
          }
        }
        return points;
      }
      function predict(x, y, t, ax, ay, p) {
        var nearPonitMaxNum = 5;
        var ponitMaxNum = 300;
        //清洗数据
        var data = loadData(ponitMaxNum, t, ax, ay);
        //找出最近的点
        var data2 = near(x, y, nearPonitMaxNum, data.t, data.x, data.y);

        return idw3(x, y, data2.t, data2.x, data2.y, p);
      }
      function loadData(maxPointNum, t, ax, ay) {
        var data = {};
        var tl = [];
        var xl = [];
        var yl = [];

        //每级跨度，向上取整
        var m = Math.ceil(t.length / maxPointNum);
        var i = m;
        var n = 0;
        while (i < t.length && n < maxPointNum) {
          tl.push(t[i]);
          xl.push(ax[i]);
          yl.push(ay[i]);
          i += m;
          n++;
        }
        data.x = xl;
        data.y = yl;
        data.t = tl;
        return data;
      }
      function near(x, y, nearPonitMaxNum, t, ax, ay) {
        var data = {};
        var ad = [];
        var tn = [];
        var xn = [];
        var yn = [];
        for (var i = 0; i < t.length; i++) {
          var wp;
          var d = Math.pow(
            Math.pow(x - ax[i], 2) + Math.pow(y - ay[i], 2),
            0.5
          );

          ad.push([i, d]);
        }

        ad.sort(function (a, b) {
          return a[1] - b[1];
        });
        ad = ad.slice(0, nearPonitMaxNum);

        var tn = [];
        var xn = [];
        var yn = [];
        for (var i = 0; i < ad.length; i++) {
          tn.push(t[ad[i][0]]);
          xn.push(ax[ad[i][0]]);
          yn.push(ay[ad[i][0]]);
        }
        data.x = xn;
        data.y = yn;
        data.t = tn;
        return data;
      }
      function idw3(x, y, t, ax, ay) {
        var s1 = 0;
        var s2 = 0;
        for (var i = 0; i < t.length; i++) {
          var d = Math.pow(
            Math.pow(x - ax[i], 2) + Math.pow(y - ay[i], 2),
            0.5
          );
          d = 1.0 / d;
          d = d * d;
          s1 += d * t[0];
          s2 += d;
        }
        return s1 / s2;
      }
      function isInArray(arr, value) {
        for (var i = 0; i < arr.length; i++) {
          if (value === arr[i]) {
            return true;
          }
        }
        return false;
      }
      function toRGBA(color) {
        var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
        var rgbColor = [];
        if (color.indexOf("rgb") > -1) {
          return color.slice(4, color.length - 1).split(",");
        }
        var sColor = color.toLowerCase();
        if (sColor && reg.test(sColor)) {
          if (sColor.length === 4) {
            var sColorNew = "#";
            for (var i = 1; i < 4; i += 1) {
              sColorNew += sColor
                .slice(i, i + 1)
                .concat(sColor.slice(i, i + 1));
            }
            sColor = sColorNew;
          }
          //处理六位的颜色值
          var sColorChange = [];
          for (var i = 1; i < 7; i += 2) {
            sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
          }
          sColorChange.push(200);
          return sColorChange;
        }
      }
      function addPolygonPlane(polylinering, color1) {
        let arr = [];
        data.modelJunctions.forEach((item) => {
          arr.push([Number(item.y), Number(item.x)]);
        });
        arr.push(arr[0]);
        let show = false;
        var poly = turf.polygon([arr]);
        var bdpoints = [];
        for (var i = 0; i < polylinering.length; i++) {
          var pt = turf.point([polylinering[i][1], polylinering[i][0]]);
          if (turf.booleanPointInPolygon(pt, poly)) show = true;
          bdpoints.push(polylinering[i][1], polylinering[i][0]);
        }
        if (show) {
          var polygon = viewer.entities.add({
            polygon: {
              hierarchy: Cesium.Cartesian3.fromDegreesArray(bdpoints),
              material: color1,
              outline: false,
            },
          });
          let polygons = [];
          polygons.push(polygon);
        }
      }
      let bands = isoband(extent, _points, gradeBreak);
      var colorIsoline = [
        "#ff0000",
        "rgb(128,0,255)",
        "#00ff00",
        "#ffff00",
        "#0000ff",
        "#ff00ff",
        "#ff8686",
        "#338833",
      ]; //(面)
      bands.forEach((band, i) => {
        var color1 = toRGBA(colorIsoline[i]);
        var cesiumColor = Cesium.Color.fromBytes(
          color1[0],
          color1[1],
          color1[2],
          color1[3]
        );
        band.coords.forEach((polygon, j) => {
          addPolygonPlane(polygon, cesiumColor);
        });
      });
    },
  },
  mounted() {
    this.initMap();
    this.setView(114.1628, 22.2795); // 香港中心点
    this.addPointsPrimitives();
    this.drawIsoline();
    // this.addPopup();
  },
};
</script>

<style>
.popup {
  position: absolute;
  background-color: #002967;
  border: 0.05rem solid #fff;
  width: 50px;
  height: 50px;
  border-radius: 0.5rem;
  padding: 1rem;
}
</style>
